From 75bfa50745e070ad3df53ee88016fb8879e3eade Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Tue, 6 Jul 2004 15:12:42 +0000 Subject: [PATCH] bitkeeper revision 1.1041.8.1 (40eac16as-X5mJEQ0g8YVoYYxLFmBg) Tidy up and simplify the Python s-expression parser. --- tools/python/xen/xend/XendDomainInfo.py | 27 +- tools/python/xen/xend/XendRoot.py | 2 +- tools/python/xen/xend/sxp.py | 536 ++++-------------------- tools/python/xen/xm/main.py | 16 +- 4 files changed, 97 insertions(+), 484 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index f14e6477c2..1269c2155c 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -291,6 +291,9 @@ def vm_restore(src, progress=0): if dom < 0: raise VmError('restore failed') vmconfig = sxp.from_string(d['vmconfig']) + if not vmconfig: + raise VmError('bad vmconfig s-expression') + vmconfig = vmconfig[0] vm.config = sxp.child_value(vmconfig, 'config') deferred = vm.dom_configure(dom) def vifs_cb(val, vm): @@ -419,8 +422,8 @@ class XendDomainInfo: self.config = config try: self.name = sxp.child_value(config, 'name') - self.memory = int(sxp.child_value(config, 'memory', '128')) - if sxp.child(config, 'autorestart', None): + self.memory = int(sxp.child_value(config, 'memory') or '128') + if sxp.child(config, 'autorestart'): self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') @@ -449,7 +452,7 @@ class XendDomainInfo: """ devices = [] for d in sxp.children(self.config, 'device'): - dev = sxp.child0(d) + dev = sxp.child(d) if dev is None: continue if name == sxp.name(dev): devices.append(dev) @@ -580,7 +583,7 @@ class XendDomainInfo: if self.recreate: return memory = self.memory name = self.name - cpu = int(sxp.child_value(self.config, 'cpu', '-1')) + cpu = int(sxp.child_value(self.config, 'cpu') or '-1') print 'init_domain>', memory, name, cpu dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu) if dom <= 0: @@ -645,7 +648,7 @@ class XendDomainInfo: devices = sxp.children(self.config, 'device') index = {} for d in devices: - dev = sxp.child0(d) + dev = sxp.child(d) if dev is None: raise VmError('invalid device') dev_name = sxp.name(dev) @@ -664,7 +667,7 @@ class XendDomainInfo: """Set configuration flags if the vm is a backend for netif of blkif. """ for c in sxp.children(self.config, 'backend'): - name = sxp.name(sxp.child0(c)) + name = sxp.name(sxp.child(c)) if name == 'blkif': self.blkif_backend = 1 elif name == 'netif': @@ -742,7 +745,7 @@ def vm_image_linux(vm, image): """ kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip", "dhcp") + ip = sxp.child_value(image, "ip") or "dhcp" if ip: cmdline += " ip=" + ip root = sxp.child_value(image, "root") @@ -751,7 +754,7 @@ def vm_image_linux(vm, image): args = sxp.child_value(image, "args") if args: cmdline += " " + args - ramdisk = sxp.child_value(image, "ramdisk", '') + ramdisk = sxp.child_value(image, "ramdisk") or '' vifs = vm.config_devices("vif") vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs)) return vm @@ -768,7 +771,7 @@ def vm_image_netbsd(vm, image): #todo: Same as for linux. Is that right? If so can unify them. kernel = sxp.child_value(image, "kernel") cmdline = "" - ip = sxp.child_value(image, "ip", "dhcp") + ip = sxp.child_value(image, "ip") or "dhcp" if ip: cmdline += "ip=" + ip root = sxp.child_value(image, "root") @@ -797,7 +800,7 @@ def vm_dev_vif(vm, val, index): defer = make_vif(vm.dom, vif, vmac, vm.recreate) def fn(id): dev = xend.netif_dev(vm.dom, vif) - devid = sxp.attribute(val, 'id') + devid = sxp.child_value(val, 'id') if devid: dev.setprop('id', devid) bridge = sxp.child_value(val, "bridge") @@ -824,7 +827,7 @@ def vm_dev_vbd(vm, val, index): dev = sxp.child_value(val, 'dev') if not dev: raise VmError('vbd: Missing dev') - mode = sxp.child_value(val, 'mode', 'r') + mode = sxp.child_value(val, 'mode') or 'r' defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): dev = xend.blkif_dev(vm.dom, vdev) @@ -926,7 +929,7 @@ def vm_field_vnet(vm, config, val, index): if id is None: raise VmError('vnet: missing vif id') dev = vm.get_device_by_id('vif', id) - #vnet = sxp.child_value(v, 'vnet', 1) + #vnet = sxp.child_value(v, 'vnet') or '1' #mac = sxp.child_value(dev, 'mac') #vif = sxp.child_value(dev, 'vif') #vnet_bridge(vnet, mac, vm.dom, 0) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index 665f5df29e..3687f57f4a 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -145,7 +145,7 @@ class XendRoot: val default value (optional, defaults to None) returns value """ - return sxp.child_value(self.config, name, val=val) + return sxp.child_value(self.config, name) or val def instance(): global inst diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py index 143ba81ab4..352f7f2933 100644 --- a/tools/python/xen/xend/sxp.py +++ b/tools/python/xen/xend/sxp.py @@ -21,56 +21,19 @@ from StringIO import StringIO __all__ = [ "mime_type", "ParseError", - "Parser", - "atomp", - "show", - "show_xml", - "elementp", + "Parser", + "show", "name", - "attributes", - "attribute", "children", "child", - "child_at", - "child0", - "child1", - "child2", - "child3", - "child4", "child_value", - "has_id", - "with_id", - "child_with_id", - "elements", "to_string", "from_string", - "all_from_string", "parse", ] mime_type = "application/sxp" -escapes = { - 'a': '\a', - 'b': '\b', - 't': '\t', - 'n': '\n', - 'v': '\v', - 'f': '\f', - 'r': '\r', - '\\': '\\', - '\'': '\'', - '\"': '\"'} - -k_list_open = "(" -k_list_close = ")" -k_attr_open = "@" -k_eval = "!" - -escapes_rev = {} -for k in escapes: - escapes_rev[escapes[k]] = k - class ParseError(StandardError): def __init__(self, parser, value): @@ -86,7 +49,6 @@ class ParserState: self.parent = parent self.buf = '' self.val = [] - self.delim = None self.fn = fn def push(self, fn): @@ -95,28 +57,19 @@ class ParserState: class Parser: def __init__(self): - self.error = sys.stderr self.reset() def reset(self): - self.val = [] self.eof = 0 - self.err = 0 self.line_no = 0 self.char_no = 0 - self.state = None + self.state = self.start_state = ParserState(self.state_start) def push_state(self, fn): self.state = self.state.push(fn) def pop_state(self): - val = self.state self.state = self.state.parent - if self.state and self.state.fn == self.state_start: - # Return to start state - produce the value. - self.val += self.state.val - self.state.val = [] - return val def in_class(self, c, s): return s.find(c) >= 0 @@ -136,12 +89,6 @@ class Parser: def in_printable_class(self, c): return self.in_class(c, string.printable) - def set_error_stream(self, error): - self.error = error - - def has_error(self): - return self.err > 0 - def at_eof(self): return self.eof @@ -166,439 +113,131 @@ class Parser: self.char_no += 1 if self.state is None: - self.begin_start(None) + self.state = ParserState(self.state_start) + self.state.fn(c) def ready(self): - return len(self.val) > 0 + return len(self.start_state.val) > 0 def get_val(self): - v = self.val[0] - self.val = self.val[1:] + v = self.start_state.val[0] + self.start_state.val = self.start_state.val[1:] return v def get_all(self): - return self.val - - def begin_start(self, c): - self.state = ParserState(self.state_start) + return self.start_state.val - def end_start(self): - self.val += self.state.val - self.pop_state() - def state_start(self, c): - if self.at_eof(): - self.end_start() - elif self.in_space_class(c): + if self.at_eof() or self.in_space_class(c): pass elif self.in_comment_class(c): - self.begin_comment(c) - elif c == k_list_open: - self.begin_list(c) - elif c == k_list_close: + self.push_state(self.state_comment) + elif c == '(': + self.push_state(self.state_list) + elif c == ')': raise ParseError(self, "syntax error: "+c) elif self.in_string_quote_class(c): - self.begin_string(c) + self.push_state(self.state_string) + self.state.buf = c elif self.in_printable_class(c): - self.begin_atom(c) + self.push_state(self.state_atom) + self.state.buf = c elif c == chr(4): # ctrl-D, EOT: end-of-text. self.input_eof() else: raise ParseError(self, "invalid character: code %d" % ord(c)) - def begin_comment(self, c): - self.push_state(self.state_comment) - self.state.buf += c - - def end_comment(self): - self.pop_state() - def state_comment(self, c): if c == '\n' or self.at_eof(): - self.end_comment() - else: - self.state.buf += c - - def begin_string(self, c): - self.push_state(self.state_string) - self.state.delim = c + self.pop_state() - def end_string(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() - def state_string(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - elif c == self.state.delim: - self.end_string() - elif c == '\\': - self.push_state(self.state_escape) - else: - self.state.buf += c - - def state_escape(self, c): - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - d = escapes.get(c) - if d: - self.state.parent.buf += d - self.pop_state() - elif c == 'x': - self.state.fn = self.state_hex - self.state.val = 0 - else: - self.state.fn = self.state_octal - self.state.val = 0 - self.input_char(c) - - def state_octal(self, c): - def octaldigit(c): - self.state.val *= 8 - self.state.val += ord(c) - ord('0') - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid octal escape: out of range " + self.state.buf) - if len(self.state.buf) == 3: - octaldone() - - def octaldone(): - d = chr(self.state.val) - self.state.parent.buf += d - self.pop_state() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '7': - octaldigit(c) - elif len(self.buf): - octaldone() - self.input_char(c) - - def state_hex(self, c): - def hexdone(): - d = chr(self.state.val) - self.state.parent.buf += d + self.state.buf += c + # Look out for non-escaped end delimiter + if self.state.buf[0] == c and self.state.buf[-2] != '\\': + try: # parse escape sequences but fall back to something simple + val = eval(compile(self.state.buf,'','eval')) + except: + val = self.state.buf[1:-1] # just strip the delimiters + self.state.parent.val.append(val) self.pop_state() - - def hexdigit(c, d): - self.state.val *= 16 - self.state.val += ord(c) - ord(d) - self.state.buf += c - if self.state.val < 0 or self.state.val > 0xff: - raise ParseError(self, "invalid hex escape: out of range " + self.state.buf) - if len(self.state.buf) == 2: - hexdone() - - if self.at_eof(): - raise ParseError(self, "unexpected EOF") - elif '0' <= c <= '9': - hexdigit(c, '0') - elif 'A' <= c <= 'F': - hexdigit(c, 'A') - elif 'a' <= c <= 'f': - hexdigit(c, 'a') - elif len(buf): - hexdone() - self.input_char(c) - - def begin_atom(self, c): - self.push_state(self.state_atom) - self.state.buf = c - - def end_atom(self): - val = self.state.buf - self.state.parent.val.append(val) - self.pop_state() def state_atom(self, c): - if self.at_eof(): - self.end_atom() - elif (self.is_separator(c) or - self.in_space_class(c) or - self.in_comment_class(c)): - self.end_atom() - self.input_char(c) + if (self.at_eof() or + self.is_separator(c) or + self.in_space_class(c) or + self.in_comment_class(c)): + val = self.state.buf + self.state.parent.val.append(val) + self.pop_state() + if not self.at_eof(): + self.input_char(c) else: self.state.buf += c - def begin_list(self, c): - self.push_state(self.state_list) - - def end_list(self): - val = self.state.val - self.state.parent.val.append(val) - self.pop_state() - def state_list(self, c): if self.at_eof(): raise ParseError(self, "unexpected EOF") - elif c == k_list_close: - self.end_list() + elif c == ')': + val = self.state.val + self.state.parent.val.append(val) + self.pop_state() else: self.state_start(c) -def atomp(sxpr): - """Check if an sxpr is an atom. - """ - if sxpr.isalnum() or sxpr == '@': - return 1 - for c in sxpr: - if c in string.whitespace: return 0 - if c in '"\'\\(){}[]<>$#&%^': return 0 - if c in string.ascii_letters: continue - if c in string.digits: continue - if c in '.-_:/~': continue - return 0 - return 1 - def show(sxpr, out=sys.stdout): """Print an sxpr in bracketed (lisp-style) syntax. """ if isinstance(sxpr, types.ListType): - out.write(k_list_open) - i = 0 + out.write('(') for x in sxpr: - if i: out.write(' ') show(x, out) - i += 1 - out.write(k_list_close) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) + out.write(' ') + out.write(')') else: - #out.write("'" + str(sxpr) + "'") out.write(repr(str(sxpr))) -def show_xml(sxpr, out=sys.stdout): - """Print an sxpr in XML syntax. - """ - if isinstance(sxpr, types.ListType): - element = name(sxpr) - out.write('<%s' % element) - for attr in attributes(sxpr): - out.write(' %s=%s' % (attr[0], attr[1])) - out.write('>') - i = 0 - for x in children(sxpr): - if i: out.write(' ') - show_xml(x, out) - i += 1 - out.write('' % element) - elif isinstance(sxpr, types.StringType) and atomp(sxpr): - out.write(sxpr) - else: - out.write(str(sxpr)) - -def elementp(sxpr, elt=None): - """Check if an sxpr is an element of the given type. - - sxpr sxpr - elt element type - """ - return (isinstance(sxpr, types.ListType) - and len(sxpr) - and (None == elt or sxpr[0] == elt)) - def name(sxpr): - """Get the element name of an sxpr. - If the sxpr is not an element (i.e. it's an atomic value) its name - is None. - - sxpr - - returns name (None if not an element). + """Get the element name of an sxpr, or None if a bad sxpr. """ - val = None if isinstance(sxpr, types.StringType): - val = sxpr - elif isinstance(sxpr, types.ListType) and len(sxpr): - val = sxpr[0] - return val - -def attributes(sxpr): - """Get the attribute list of an sxpr. - - sxpr - - returns attribute list - """ - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - attr = sxpr[1] - if elementp(attr, k_attr_open): - val = attr[1:] - return val - -def attribute(sxpr, key, val=None): - """Get an attribute of an sxpr. - - sxpr sxpr - key attribute key - val default value (default None) - - returns attribute value - """ - for x in attributes(sxpr): - if x[0] == key: - val = x[1] - break - return val + return sxpr + if isinstance(sxpr, types.ListType) and len(sxpr): + return sxpr[0] + return None def children(sxpr, elt=None): - """Get children of an sxpr. - - sxpr sxpr - elt optional element type to filter by - - returns children (filtered by elt if specified) + """Get children of an s-expression @sxpr, optionally filtered by + element type @elt. """ - val = [] - if isinstance(sxpr, types.ListType) and len(sxpr) > 1: - i = 1 - x = sxpr[i] - if elementp(x, k_attr_open): - i += 1 - val = sxpr[i : ] + if not isinstance(sxpr, types.ListType): return [] + val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr) if elt: - def iselt(x): - return elementp(x, elt) - val = filter(iselt, val) - return val - -def child(sxpr, elt, val=None): - """Get the first child of the given element type. - - sxpr sxpr - elt element type - val default value - """ - for x in children(sxpr): - if elementp(x, elt): - val = x - break - return val - -def child_at(sxpr, index, val=None): - """Get the child at the given index (zero-based). - - sxpr sxpr - index index - val default value - """ - kids = children(sxpr) - if len(kids) > index: - val = kids[index] - return val - -def child0(sxpr, val=None): - """Get the zeroth child. - """ - return child_at(sxpr, 0, val) - -def child1(sxpr, val=None): - """Get the first child. - """ - return child_at(sxpr, 1, val) - -def child2(sxpr, val=None): - """Get the second child. - """ - return child_at(sxpr, 2, val) - -def child3(sxpr, val=None): - """Get the third child. - """ - return child_at(sxpr, 3, val) - -def child4(sxpr, val=None): - """Get the fourth child. - """ - return child_at(sxpr, 4, val) - -def child_value(sxpr, elt, val=None): - """Get the value of the first child of the given element type. - Assumes the child has an atomic value. - - sxpr sxpr - elt element type - val default value - """ - kid = child(sxpr, elt) - if kid: - val = child_at(kid, 0, val) + val = filter(lambda x,y=elt: x[0] == y, val) return val -def has_id(sxpr, id): - """Test if an s-expression has a given id. +def child(sxpr, elt=None, idx=0): + """Get the @idx'th child of the optional filtering type @elt in @sxpr. """ - return attribute(sxpr, 'id') == id - -def with_id(sxpr, id, val=None): - """Find the first s-expression with a given id, at any depth. - - sxpr s-exp or list - id id - val value if not found (default None) + x = children(sxpr, elt) + if len(x) > idx: + return x[idx] + return None - return s-exp or val +def child_value(sxpr, elt=None): + """Get the value of the first child of @sxpr with the optional type @elt. """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - v = with_id(n, id) - if v is None: continue - val = v - break - return val - -def child_with_id(sxpr, id, val=None): - """Find the first child with a given id. - - sxpr s-exp or list - id id - val value if not found (default None) - - return s-exp or val - """ - if isinstance(sxpr, types.ListType): - for n in sxpr: - if has_id(n, id): - val = n - break - return val - -def elements(sxpr, ctxt=None): - """Generate elements (at any depth). - Visit elements in pre-order. - Values generated are (node, context) - The context is None if there is no parent, otherwise - (index, parent, context) where index is the node's index w.r.t its parent, - and context is the parent's context. - - sxpr s-exp - - returns generator - """ - yield (sxpr, ctxt) - i = 0 - for n in children(sxpr): - if isinstance(n, types.ListType): - # Calling elements() recursively does not generate recursively, - # it just returns a generator object. So we must iterate over it. - for v in elements(n, (i, sxpr, ctxt)): - yield v - i += 1 + x = child(sxpr, elt) + if not isinstance(x, types.ListType) or len(x) < 2: + return None + return x[1] def to_string(sxpr): - """Convert an sxpr to a string. - - sxpr sxpr - returns string + """Convert an s-expression @sxpr to a string. """ io = StringIO() show(sxpr, io) @@ -608,35 +247,14 @@ def to_string(sxpr): return val def from_string(str): - """Create an sxpr by parsing a string. - - str string - returns sxpr - """ - io = StringIO(str) - vals = parse(io) - if vals is []: - return None - else: - return vals[0] - - -def all_from_string(str): - """Create an sxpr list by parsing a string. - - str string - returns sxpr list + """Create an sxpr list from a given input string @str. """ io = StringIO(str) vals = parse(io) return vals def parse(io): - """Completely parse all input from 'io'. - - io input file object - returns list of values, None if incomplete - raises ParseError on parse error + """Completely parse all input from file @io. """ pin = Parser() while 1: @@ -649,19 +267,11 @@ def parse(io): else: val = None return val - + if __name__ == '__main__': - print ">main" pin = Parser() - while 1: - buf = sys.stdin.read(1024) - #buf = sys.stdin.readline() - pin.input(buf) - while pin.ready(): - val = pin.get_val() - print - print '****** val=', val - if len(buf) == 0: - break - + buf = sys.stdin.read(1024) + pin.input(buf) + while pin.ready(): + print '\n****** val=', pin.get_val() diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 97a36f6711..9ae1fb67b8 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -246,11 +246,11 @@ class ProgList(Prog): info = server.xend_domain(dom) d = {} d['dom'] = int(dom) - d['name'] = sxp.child_value(info, 'name', '??') - d['mem'] = int(sxp.child_value(info, 'memory', '0')) - d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) - d['state'] = sxp.child_value(info, 'state', '??') - d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) + d['name'] = sxp.child_value(info, 'name') or '??' + d['mem'] = int(sxp.child_value(info, 'memory') or '-1') + d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1') + d['state'] = sxp.child_value(info, 'state') or '??' + d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1') print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d) def long_list(self, doms): @@ -424,9 +424,9 @@ class ProgConsoles(Prog): for x in l: info = server.xend_console(x) d = {} - d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1] - d['port'] = sxp.child_value(info, 'port', '?') - d['id'] = sxp.child_value(info, 'id', '?') + d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1] + d['port'] = sxp.child_value(info, 'port') or '?' + d['id'] = sxp.child_value(info, 'id') or '?' print "%(dom)3s %(port)4s %(id)3s" % d xm.prog(ProgConsoles) -- 2.30.2